package utils;


import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.*;
import java.util.HashMap;
import java.util.Map;

/**
 * @Description 根据链接数据库表名生成对应实体类
 * @Date 2024/10/10 17:58
 * @Author xiWei
 */
public class TestFromToObject {
    public static void main(String[] args) {
        String path = "D:\\NJGT\\build_table";
        String table = "t_syxcjxx";
        fromToObject(table, path);
    }

    //该对象用于存放表字段转换成属性的字符串
    static StringBuilder objStr = new StringBuilder();

    private static Connection Conn() {
        //String url = "jdbc:postgresql://192.168.1.179:5432/gt_db_v2.0?userUnicode=true&characterEncoding=utf8";
        String url = "jdbc:mysql://192.168.1.179:3306/qgwf_kss?userUnicode=true&characterEncoding=utf8";
        String user = "root";
        String password = "123";
        Connection connection = null;
        try {
            connection = DriverManager.getConnection(url, user, password);
            System.out.println("\n==============数据库连接成功==============");
            return connection;
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("\n============连接失败,请查看错误信息============");
            return connection;
        }
    }

    //首字母大写的方法
    private static String upFirstCode(String str) {
        return str.substring(0, 1).toUpperCase()
                + str.substring(1);
    }

    //下划线命名转化驼峰命名的方法
    private static String humpString(String str, Integer type) {
        StringBuilder finalStr = new StringBuilder();
        String[] arr = str.split("_");
        if (type == 0) {
            for (String s : arr) {
                String str2 = upFirstCode(s);
                finalStr.append(str2);
            }
        } else if (type == 1) {
            //首字母不大写,先拼接第一个单词（即分割的数组的第0号元素）
            finalStr.append(arr[0]);
            for (int i = 1; i < arr.length; i++) {
                String str2 = upFirstCode(arr[i]);
                finalStr.append(str2);
            }
        }
        return finalStr.toString();
    }

    //转换表字段到字符串的方法
    private static void getTableField(Connection conn, String fromName) {
        PreparedStatement pst = null;
        ResultSet rs = null;
        try {
            objStr.append("import lombok.Data;\nimport javax.persistence.Table;\nimport java.util.Date;\n@Data\n@Table(name=\"");
            objStr.append(fromName);
            objStr.append("\")\n");
            objStr.append("public class ").append(humpString(fromName, 0)).append("{\n");

            // 获取表字段注释
            DatabaseMetaData metaData = conn.getMetaData();
            ResultSet columns = metaData.getColumns(null, null, fromName, null);
            Map<String, String> columnComments = new HashMap<>();

            while (columns.next()) {
                String columnName = columns.getString("COLUMN_NAME");
                String columnComment = columns.getString("REMARKS");
                columnComments.put(columnName, columnComment);
            }

            // 查询表数据获取字段类型
            String sql = "SELECT * FROM " + fromName + " LIMIT 1";
            pst = conn.prepareStatement(sql);
            rs = pst.executeQuery();
            ResultSetMetaData rsMd = rs.getMetaData();

            for (int i = 1; i <= rsMd.getColumnCount(); i++) {
                String columnName = rsMd.getColumnName(i);
                String className = rsMd.getColumnClassName(i);
                String[] javaType = className.split("\\.");
                String finalJavaType = javaType[javaType.length - 1];
                String fieldName = humpString(columnName, 1);
                fieldName = fieldName.toLowerCase();

                System.out.print((i) + "." + "字段名称是：" + fieldName + " ");
                System.out.println("字段类型是：" + finalJavaType);

                // 添加字段注释
                if (columnComments.containsKey(columnName) && !columnComments.get(columnName).isEmpty()) {
                    objStr.append("\n\t/** ").append(columnComments.get(columnName)).append(" */");
                }
                if (finalJavaType.equals("Timestamp")) {
                    finalJavaType = "Date";
                }
                if (finalJavaType.equals("LocalDateTime")) {
                    finalJavaType = "Date";
                }
                if (finalJavaType.equals("[B")) {
                    finalJavaType = "Byte[]";
                }
                objStr.append("\n\tprivate ").append(finalJavaType).append(" ").append(fieldName).append(";\n");
            }
            objStr.append("}");
            System.out.println("===========================================");
            System.out.println("该表生成的实体类字符串如下:\n" + objStr);
        } catch (SQLException e) {
            e.printStackTrace();
            System.out.println("\n===============您输入的表名可能不存在===============");
        } finally {
            try {
                if (rs != null) rs.close();
                if (pst != null) pst.close();
                if (conn != null) conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    //使用io流，将字符串写入文件输出到磁盘上的方法
    private static void StrToObject(String path, String fromName) {
        FileOutputStream fileOutputStream = null;
        try {   //该变量用于记录java文件夹的位置,以便获取实体类对应的软件包位置
            int packNum = 0;
            StringBuilder packName = new StringBuilder("package ");
            String[] arr = path.split("\\\\");
            for (int i = 0; i < arr.length; i++) {
                if (arr[i].equals("java")) {
                    packNum = i + 1;
                    break;
                }
            }
            for (int i = packNum; i < arr.length; i++) {
                packName.append(arr[i]);
                if (i == arr.length - 1) {
                    break;
                }
                packName.append(".");
            }

            System.out.println("\n\n该实体类应处于的软件包位置是：" + packName);
            fileOutputStream = new FileOutputStream(path + "\\\\" + humpString(fromName, 0) + ".java");
            //fileOutputStream.write(packName.toString().getBytes());
            fileOutputStream.write("\n".getBytes());
            fileOutputStream.write(objStr.toString().getBytes());

            System.out.println("实体类生成完成，请至对应的输出路径下查看");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            System.out.println("文件路径指定异常");
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("写入异常");
        } finally {
            try {
                if (fileOutputStream != null) {
                    fileOutputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    //暴露给外部的调用方法
    public static void fromToObject(String table, String path) {
        /*System.out.println("请先导入lombok再使用，若还没有导入，\n再输入连接数据库的名称的时候输入" +
                "\n 0exit0 \n来退出");
        Scanner sc = new Scanner(System.in);
        System.out.println("请要连接的数据库名");
        String tableName = sc.next();
        if("0exit0".equals(tableName))
        {
            System.out.println("退出成功");
            System.exit(0);
        }*/
       /* System.out.println("请输入要转化成实体类的表名");
        String fromName = sc.next();
        System.out.println("请输入实体类要存放的路径(绝对路径)");
        String pathName = sc.next();*/
        //连接数据库获取表字段并转换成字符串
        getTableField(Conn(), table);
        //使用io流写入文件到指定位置
        StrToObject(path, table);
    }
}
